import { is, getBusinessObject, isAny } from 'bpmn-js/lib/util/ModelUtil'
import { getSignalEventDefinition } from './bpmnPropertyUtils/eventDefinition'
import { createModdleElement, getExtensionElementsList, addExtensionElements, removeExtensionElements } from './bpmnPropertyUtils/extensionElements'
import { filter } from 'min-dash'
import { useSettingStore } from '@/store/bpmnProcess/settingStore'
import { useModelerStore } from '@/store/bpmnProcess/modelerStore'

export function areOutMappingsSupported(element) {
  return is(element, 'bpmn:CallActivity')
}

export function areInMappingsSupported(element) {
  const signalEventDefinition = getSignalEventDefinition(element)
  if (signalEventDefinition) {
    return isAny(element, ['bpmn:IntermediateThrowEvent', 'bpmn:EndEvent'])
  }
  return is(element, 'bpmn:CallActivity')
}

export function getMappingPropagateAll(element, type) {
  return type === 'InMapping' ? isInMappingPropagateAll(element) : isOutMappingPropagateAll(element)
}
export function setMappingPropagateAll(element, type, value) {
  if (value) {
    type === 'InMapping' ? addInMapping(element) : addOutMapping(element)
  } else {
    type === 'InMapping' ? removeInMapping(element) : removeOutMapping(element)
  }
}

export function getMappingLocal(element, type) {
  const prefix = useSettingStore().editor.processEngine
  const mapping = type === 'InMapping' ? findRelevantInMappings(element)[0] : findRelevantOutMappings(element)[0]
  return mapping.get(`${prefix}:local`)
}
export function setMappingLocal(element, type, value) {
  const modeling = useModelerStore().getModeling
  const mapping = type === 'InMapping' ? findRelevantInMappings(element)[0] : findRelevantOutMappings(element)[0]
  modeling.updateModdleProperties(element, mapping, { local: value })
}

export function getMappingList(element, type) {
  if (type === 'InMapping') {
    return getInMappings(element) || []
  } else {
    return getOutMappings(element) || []
  }
}

export function addMapping(element, type, props) {
  const prefix = useSettingStore().editor.processEngine
  let businessObject = null
  let newMapping = null
  const result: any = {
    target: props.target,
    local: props.local
  }
  if (props.type === 'source') {
    result['source'] = props.source
  } else {
    result['sourceExpression'] = props.source
  }
  if (type === 'InMapping') {
    businessObject = getSignalEventDefinition(element) || getBusinessObject(element)
    newMapping = createModdleElement(`${prefix}:In`, result, null)
  } else {
    businessObject = getBusinessObject(element)
    newMapping = createModdleElement(`${prefix}:Out`, result, null)
  }
  addExtensionElements(element, businessObject, newMapping)
}

export function editMapping(element, type, props, index) {
  const modeling = useModelerStore().getModeling
  const mappings = getMappingList(element, type)
  const result: any = {
    target: props.target,
    local: props.local
  }
  if (props.type === 'source') {
    result['source'] = props.source
    result['sourceExpression'] = undefined
  } else {
    result['source'] = undefined
    result['sourceExpression'] = props.source
  }
  modeling.updateModdleProperties(element, mappings[index], result)
}

export function removeMapping(element, type, props) {
  let businessObject = null
  if (type === 'InMapping') {
    businessObject = getSignalEventDefinition(element) || getBusinessObject(element)
  } else {
    businessObject = getBusinessObject(element)
  }
  removeExtensionElements(element, businessObject, props)
}

function addInMapping(element) {
  const prefix = useSettingStore().editor.processEngine
  const businessObject = getSignalEventDefinition(element) || getBusinessObject(element)
  const mapping = createModdleElement(`${prefix}:In`, { variables: 'all' }, null)
  addExtensionElements(element, businessObject, mapping)
}
function removeInMapping(element) {
  const businessObject = getSignalEventDefinition(element) || getBusinessObject(element)
  const mappings = findRelevantInMappings(element)
  removeExtensionElements(element, businessObject, mappings)
}
function addOutMapping(element) {
  const prefix = useSettingStore().editor.processEngine
  const businessObject = getBusinessObject(element)
  const mapping = createModdleElement(`${prefix}:Out`, { variables: 'all' }, null)
  addExtensionElements(element, businessObject, mapping)
}
function removeOutMapping(element) {
  const businessObject = getBusinessObject(element)
  const mappings = findRelevantOutMappings(element)
  removeExtensionElements(element, businessObject, mappings)
}

function isInMappingPropagateAll(element) {
  const mappings = findRelevantInMappings(element)
  return !!mappings.length
}
function getInMappingsForPropagate(element) {
  const prefix = useSettingStore().editor.processEngine
  const businessObject = getBusinessObject(element)
  const signalEventDefinition = getSignalEventDefinition(businessObject)
  return getExtensionElementsList(signalEventDefinition || businessObject, `${prefix}:In`)
}
function findRelevantInMappings(element) {
  const inMappings = getInMappingsForPropagate(element)
  return filter(inMappings, function (mapping) {
    const variables = mapping.get('variables')
    return variables && variables === 'all'
  })
}

function isOutMappingPropagateAll(element) {
  const mappings = findRelevantOutMappings(element)
  return !!mappings.length
}
function getOutMappingsForPropagate(element) {
  const prefix = useSettingStore().editor.processEngine
  const businessObject = getBusinessObject(element)
  return getExtensionElementsList(businessObject, `${prefix}:Out`)
}
function findRelevantOutMappings(element) {
  const outMappings = getOutMappingsForPropagate(element)
  return filter(outMappings, function (mapping) {
    const variables = mapping.get('variables')
    return variables && variables === 'all'
  })
}

export function getSourceTypeOptions() {
  return [
    {
      label: '源',
      value: 'source'
    },
    {
      label: '源表达式',
      value: 'sourceExpression'
    }
  ]
}

export function getInOutType(mapping) {
  let inOutType = ''
  if (typeof mapping.source !== 'undefined') {
    inOutType = 'source'
  } else if (typeof mapping.sourceExpression !== 'undefined') {
    inOutType = 'sourceExpression'
  }
  return inOutType
}

function getInMappings(element) {
  const prefix = useSettingStore().editor.processEngine
  const businessObject = getBusinessObject(element)
  const signalEventDefinition = getSignalEventDefinition(businessObject)
  const mappings = getExtensionElementsList(signalEventDefinition || businessObject, `${prefix}:In`)

  // only retrieve relevant mappings here, others are handled in other groups
  // mapping.businessKey => camunda-platform/CallAvtivityProps
  // mapping.variables => camunda-platform/InMappingPropagationProps
  return filter(mappings, function (mapping) {
    return !mapping.businessKey && !(mapping.variables && mapping.variables === 'all')
  })
}

function getOutMappings(element) {
  const prefix = useSettingStore().editor.processEngine
  const businessObject = getBusinessObject(element)
  const mappings = getExtensionElementsList(businessObject, `${prefix}:Out`)

  // only retrieve relevant mappings here, others are handled in other groups
  // mapping.businessKey => camunda-platform/CallAvtivityProps
  // mapping.variables => camunda-platform/OutMappingPropagationProps
  return filter(mappings, function (mapping) {
    return !mapping.businessKey && !(mapping.variables && mapping.variables === 'all')
  })
}
